
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <pthread.h>
#include <stdarg.h>
#include <sys/time.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "cJSON.h"
#include "ts_mqtt.h"
#include "ts_thread.h"
#include "../include/app.h"
#include "utils_common.h"
#include "tcpprox.h"
#include "utils_sys.h"
#include "utils_thread.h"
#include "app.h"

#define MQTT_CONFIG_FILE "mqconfig.json"
#define DEV_CONFIG_FILE "./devconfig.json"

typedef struct DevConfigInfo
{
    char dev_type[32]; // 设备类型（类型1、车道2、缴费机3、巡检车）
    char du_id[64];    // 设备唯一ID
    char pj_id[64];    // 项目相关信息，如项目ID
} DEVCONFIG_S;

extern DEVCONFIG_S g_devconfig;

extern void lprintf(const char *fmt, ...);
extern void trace_log(const char *fmt, ...);

static char device_id[128] = {0};
static HANDLE gMQHandle = NULL;
static void (*CoreCallApi)(int type, char *buff) = NULL;
DEVCONFIG_S g_devconfig = {0};
typedef struct tagDevObject
{
    int magic;
} DEVOBJECTS;

// 设备端配置信息
static const char *defaultDevJsonCfg =
    "{\r\n"
    "    \"server_addr\": \"mqtt://172.16.13.155:1883\",\r\n"
    "    \"heartBeatEnable\": true,\r\n"
    "    \"heartbeat_interval\": 30000,\r\n"
    "    \"device\": {\r\n"
    "        \"DTYPE\": \"1000\",\r\n"              // 设备类型
    "        \"DUID\": \"TV_202311_55667788\",\r\n" // 设备唯一标识符，由设备类型_生产年月_设备SN编号
    "        \"PJID\": \"\"\r\n"                    // 项目相关信息，数字或英文字符串
    "    }\r\n"
    "}";

static int64_t GetUtcTimeStamp()
{
    int64_t tick = 0;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    localtime(&tv.tv_sec);
    tick = (int64_t)tv.tv_sec;
    return tick;
}

static const char *get_msgId()
{
    static char buffer[256] = {0};
    struct timeval tv;
    struct tm *tm;
    gettimeofday(&tv, NULL);
    tm = localtime(&tv.tv_sec);
    sprintf(buffer, "%s_%04d%02d%02d%02d%02d%02d%03d",
            g_devconfig.pj_id, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
            tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec / 1000));
    return buffer;
}

// 上报设备状态
static const char *create_status_msg(const char *status)
{
    const char *val = NULL;
    static char buffer[512] = {0};
    cJSON *json = cJSON_CreateObject();
    cJSON *item = cJSON_CreateObject();
    cJSON_AddStringToObject(json, "status", status);
    cJSON_AddNumberToObject(json, "timestamp", GetUtcTimeStamp());
    cJSON_AddStringToObject(item, "DTYPE", g_devconfig.dev_type);
    cJSON_AddStringToObject(item, "DUID", device_id);
    cJSON_AddStringToObject(item, "PJID", g_devconfig.pj_id);
    cJSON_AddItemToObject(json, "data", item);
    val = cJSON_PrintUnformatted(json);
    cJSON_Delete(json);
    strcpy(buffer, val);
    return buffer;
}

// 设备端响应上报内容
static const char *create_response_msg(const char *msgId)
{
    static char buffer[256] = {0};
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "cmd", "response");
    cJSON_AddNumberToObject(root, "timestamp", GetUtcTimeStamp());
    cJSON_AddNumberToObject(root, "code", 0);
    cJSON_AddStringToObject(root, "msg", "success");
    strcpy(buffer, cJSON_PrintUnformatted(root));
    cJSON_Delete(root);
    return buffer;
}

// 上报响应结果
static void publish_bridge_info(const char *client_id, int code, const char *msg)
{
    char topic[128] = {0};
    char buffer[256] = {0};
    sprintf(topic, "iot/%s/status", client_id);
    sprintf(buffer, "{\"code\":%d,\"msg\":\"%s\"}", code, msg);
    MQClient_Publish(gMQHandle, 0, topic, buffer, 0);
}

// 上报查询结果
static void parse_json_bridge(cJSON *json)
{
    static int64_t ltLastBridge = 0;
    static int connect_count = 0;
    const char *client_id = NULL;
    const char *server_ip = NULL;
    const char *bridge_ip = NULL;
    int server_port = 0;
    int bridge_port = 0;
    client_id = json_get_string_safe(json, "client_id", "no_client_1234");
    server_ip = json_get_string_safe(json, "server_ip", NULL);
    server_port = json_get_int_safe(json, "server_port", 1025);
    bridge_ip = json_get_string_safe(json, "bridge_ip", "127.0.0.1");
    bridge_port = json_get_int_safe(json, "bridge_port", 23);
    printf("tick:%lld\r\n", get_sys_tick64());
    if ((ltLastBridge + 1000) > get_sys_tick64())
    {
        connect_count++;
    }
    else
    {
        connect_count = 0;
        ltLastBridge = get_sys_tick64();
    }
    if (connect_count > 10)
    {
        publish_bridge_info(client_id, 500, "架线繁忙");
        return;
    }
    printf("conncet to server:%s port:%d \r\n", server_ip, server_port);
    if (!server_ip || inet_addr(server_ip) == -1)
    {
        publish_bridge_info(client_id, 100, "服务器地址非法");
        printf("服务器IP地址错误\r\n");
        return;
    }
    if (0 == Dev_open_line(server_ip, server_port, bridge_ip, bridge_port))
    {
        publish_bridge_info(client_id, 0, "联机成功");
    }
    else
    {
        publish_bridge_info(client_id, 200, "架线失败");
    }
}

// 解析查询命令
static void pasre_json_request(cJSON *json)
{
    const char *cmd = NULL;
    const char *type = NULL;
    type = json_get_string_safe(json, "type", NULL);
    if (strcmp(type, "shell") == 0)
    {
        cmd = json_get_string_safe(json, "cmd", NULL);
        if (strcmp(cmd, "reboot") == 0)
        {
            trace_log("重启设备\r\n");
        }
        else
        {
            trace_log("未知命令\r\n");
        }
    }
    else if (strcmp(type, "register") == 0)
    {
    }
    else
    {
    }
}

static void onMqttEvent(HANDLE h, int code, RecvMessageS *msg)
{
    char topic[128] = {0};
    char buffer[512] = {0};
    const char *text = NULL;
    cJSON *json = NULL;
    switch (code)
    {
    case MQ_EVT_ONLINE:
        sprintf(topic, "iot/%s/online", g_devconfig.dev_type);
        text = create_status_msg("online");
        MQClient_Publish(gMQHandle, 0, topic, text, 0);
        break;
    case MQ_EVT_OFFLINE:
        break;
    case MQ_EVT_HEARTBEAT:
        break;
    case MQ_EVT_DATAREADY:
        // 判断topic
        printf("msg topic ==> %s\r\n", msg->topic);
        strcpy(topic, msg->topic);
        strncpy(buffer, msg->text, msg->len);
        json = cJSON_Parse(buffer);
        if (!json)
        {
            trace_log("Error parsing\r\n");
            return;
        }
        if (strcmp(topic, "iot/query") == 0)
        {
            sprintf(topic, "iot/devices/info", g_devconfig.dev_type);
            text = create_status_msg("info");
            MQClient_Publish(gMQHandle, 0, topic, text, 0);
        }
        else if (strstr(topic, "query"))
        {
            sprintf(topic, "iot/%s/info", g_devconfig.dev_type);
            text = create_status_msg("info");
            MQClient_Publish(gMQHandle, 0, topic, text, 0);
        }
        else if (strstr(topic, "bridge"))
        {
            parse_json_bridge(json);
        }
        else if (strstr(topic, "request"))
        {
            pasre_json_request(json);
        }
        else
        {
            trace_log("未知主题\r\n");
        }
        break;
    default:
        break;
    }
    cJSON_Delete(json);
}

static void loadSysconfig()
{
    MQTTClientConfig cfg = {0};
    int size = 0;
    char topic[256] = {0};
    cJSON *node = NULL;
    const char *content = NULL;
    const char *buffer = NULL;
    char strip_buffer[2048] = {0};
    if (access(DEV_CONFIG_FILE, F_OK) != 0)
        write_file_raw(DEV_CONFIG_FILE, (void *)defaultDevJsonCfg, strlen(defaultDevJsonCfg));
    buffer = read_file_raw(DEV_CONFIG_FILE, &size);
    string_remove_head_tail_space(buffer, strip_buffer);
    free((void *)buffer);
    cJSON *root = cJSON_Parse(strip_buffer);
    if (!root)
    {
        trace_log("parse json config error.\r\n%s\r\n", strip_buffer);
        return;
    }
    trace_log("load Dev config success.\r\n");
    strcpy(cfg.mqtt_url, json_get_string_safe(root, "server_addr", "mqtt://0.0.0.0:1883"));
    cfg.mqtt_heartBeatEnable = json_get_bool_safe(root, "mqtt_heartBeatEnable", FALSE);
    cfg.mqtt_heartBeatInterval = json_get_int_safe(root, "mqtt_heartBeatInterval", 30000);
    strcpy(cfg.mqtt_username, json_get_string_safe(root, "mqtt_username", "transpeed"));
    strcpy(cfg.mqtt_password, json_get_string_safe(root, "mqtt_password", "runwell2024!"));
    // 设置遗嘱消息

    strcpy(cfg.mqtt_url, MQTT_URL);
    strcpy(cfg.mqtt_username, MQTT_USER_NAME);
    strcpy(cfg.mqtt_password, MQTT_PASSWORD);
    trace_log("mqtt Url:%s.\r\n", cfg.mqtt_url);

    cJSON *device = cJSON_GetObjectItem(root, "device");
    strcpy(g_devconfig.dev_type, json_get_string_safe(device, "DEVTYPE", "1000"));
    strcpy(g_devconfig.du_id, json_get_string_safe(device, "DUID", "1231231231"));
    strcpy(g_devconfig.pj_id, json_get_string_safe(device, "PJID", "1231231231"));
    srandom(get_sys_tick64());
    sprintf(device_id, "%s-%04d", g_devconfig.du_id, (int)random() % 10000);
    sprintf(cfg.mqtt_client_id, "device_client%s", device_id);
    cfg.will_retain = 1;
    sprintf(topic, "iot/%s/offline", g_devconfig.dev_type);
    strcpy(cfg.mqtt_will_topic, topic);
    strcpy(cfg.mqtt_willmsg, "offline");
    trace_log("mqtt login user %s pwd:%s \r\n", cfg.mqtt_username, cfg.mqtt_password);
    cJSON_Delete(root);
    MQService_Init();
    gMQHandle = MQClient_New(&cfg, onMqttEvent);
    if (!gMQHandle)
    {
        trace_log("MQClient_New error.\r\n");
        return;
    }
    // 注册订阅主题
    sprintf(topic, "iot/query", g_devconfig.dev_type);
    MQClient_SubPreDefined(gMQHandle, 0, topic);
    sprintf(topic, "iot/%s/query", g_devconfig.dev_type);
    MQClient_SubPreDefined(gMQHandle, 0, topic);
    sprintf(topic, "iot/%s/bridge", device_id);
    MQClient_SubPreDefined(gMQHandle, 0, topic);
    sprintf(topic, "iot/%s/request", device_id);
    MQClient_SubPreDefined(gMQHandle, 0, topic);
    MQService_Enable(1);
}

void service_run()
{
    int chr;
    int bQuit = 0;
    char topic[128] = {0};
    LoadCodeTable();
    THREAD_initialize();
    loadSysconfig();
    ProxyStart();
}

void service_stop()
{
}
